#include "esp8266.h"

// -------------内部变量-------------
uint8_t espRecvData[16];
uint8_t espSendData[16];

// ------------内部定义----------------
#define ESP8266_Port GPIOB
#define ESP8266_Pin_Tx GPIO_Pin_10
#define ESP8266_Pin_Rx GPIO_Pin_11
#define ESP8266_Pin_En GPIO_Pin_8
#define ESP8266_Pin_Rst GPIO_Pin_9

#define ESP8266_UART USART3

#define ESP8266_Baudrate 115200

#define ESP8266_DMA_TX_Channel DMA1_Channel2
#define ESP8266_DMA_Rx_Channel DMA1_Channel3

void ESP8266_Init(void)
{
    // -------------RCC-----------------
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    //---------先配置GPIO---------------
    // tx
    GPIO_InitTypeDef gpio_initStruct = {0};
    gpio_initStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio_initStruct.GPIO_Speed = GPIO_Speed_10MHz;
    gpio_initStruct.GPIO_Pin = ESP8266_Pin_Tx;
    GPIO_Init(ESP8266_Port, &gpio_initStruct);
    // rx
    gpio_initStruct.GPIO_Mode = GPIO_Mode_IPU;
    gpio_initStruct.GPIO_Pin = ESP8266_Pin_Rx;
    GPIO_Init(ESP8266_Port, &gpio_initStruct);
    // pd / rst
    gpio_initStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    gpio_initStruct.GPIO_Pin = ESP8266_Pin_En | ESP8266_Pin_Rst;
    GPIO_Init(ESP8266_Port, &gpio_initStruct);

    // ----------配置GPIO后直接拉高EN和RST, 启动ESP8266----
    GPIO_SetBits(ESP8266_Port, ESP8266_Pin_En | ESP8266_Pin_Rst);
    mySYSTICK_delayMs(1000);

    //---------再配置UART---------------
    // 最常用的配置模式, 8bit数据位, 1bit起始位, 1bit停止位, 无校验
    // 简写:  8/1/1, none
    USART_InitTypeDef usart_initStruct = {0};
    // 波特率: 通常是4800/9600/115200等
    usart_initStruct.USART_BaudRate = ESP8266_Baudrate;
    // 硬件流控: 大部分不再使用硬件流控
    usart_initStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //  发送和接收单独功能是否开启
    usart_initStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    // 校验: 奇校验/偶校验/无校验, 基本使用no
    usart_initStruct.USART_Parity = USART_Parity_No;
    usart_initStruct.USART_StopBits = USART_StopBits_1;
    usart_initStruct.USART_WordLength = USART_WordLength_8b;
    USART_Init(ESP8266_UART, &usart_initStruct);

    // TC标志位默认是1, 容易导致第一个发送的字节被忽略, 因此初始化的时候手动清零
    USART_GetFlagStatus(ESP8266_UART, USART_FLAG_TC);

    //-------------配置中断---------------------
    // 先配置中断源
    // 1. RXNE中断, 用于接收数据(此处改用DMA直接收)
    // USART_ITConfig(ESP8266_UART, USART_IT_RXNE, ENABLE);
    // 2. IDLE中断, 用于判断一帧数据结束, 可以进行分析和执行
    USART_ITConfig(ESP8266_UART, USART_IT_IDLE, ENABLE);

    // 中断通道开启
    NVIC_InitTypeDef nvic_initStruct = {0};
    // 对应的中断通道, 在stm3210x.h中枚举定义
    nvic_initStruct.NVIC_IRQChannel = USART3_IRQn;
    // 抢占优先级
    nvic_initStruct.NVIC_IRQChannelPreemptionPriority = 2;
    // 响应优先级
    nvic_initStruct.NVIC_IRQChannelSubPriority = 2;
    // 使能或禁用选项
    nvic_initStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_initStruct);

    //------------配置DMA功能-----------------
    USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);

    // 准备结构体初始化
    DMA_InitTypeDef dma_initStruct = {0};
    // 外设的地址, 此处对应USART3_RX对应的数据寄存器,即USART1->DR
    dma_initStruct.DMA_PeripheralBaseAddr = (uint32_t)(&ESP8266_UART->DR);
    // 存储器的地址, 对应内存中的某个地址, 此处使用普通内存的目标地址
    dma_initStruct.DMA_MemoryBaseAddr = (uint32_t)espRecvData;
    // direction 表示方向
    dma_initStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    // 要传输的数据个数
    dma_initStruct.DMA_BufferSize = sizeof(espRecvData);
    // 是否使用地址递增, 使用的话, 源地址和目标地址每发送一个数据都递增
    dma_initStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dma_initStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    // 存储器和外设对应的数据宽度
    dma_initStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 源地址每次读取一个字节
    dma_initStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         // 发送端每次接收一个字节
    // 是否循环dma传输, 此处选否, 传完字节即停止
    dma_initStruct.DMA_Mode = DMA_Mode_Normal;
    // 优先级, 总线资源不够时, 优先保证高优先级的通道运行
    // 四级: 低 中 高 非常高
    dma_initStruct.DMA_Priority = DMA_Priority_Medium;
    // M2M模式, 如果两头都是存储器则设为Enable, 否则Disable
    dma_initStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(ESP8266_DMA_Rx_Channel, &dma_initStruct);

    // 开启外设
    DMA_Cmd(ESP8266_DMA_Rx_Channel, ENABLE);
    USART_Cmd(USART3, ENABLE);
}
